package daos;

import java.net.UnknownHostException;

import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.Session;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;

import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;

import servicios.Operation;

public class SessionManager {
	
	private static SessionFactory sessionFactory;
	private static ThreadLocal<Session> tlSession = new ThreadLocal<Session>();
	private static ServiceRegistry serviceRegistry;
	private static ThreadLocal<GraphDatabaseService> graphSession = new ThreadLocal<GraphDatabaseService>();
	private static GraphDatabaseService graphDB;
	private static ThreadLocal<DB> MongoSession = new ThreadLocal<DB>();
	private static MongoClient mongoService;

	
	/**
	 * Crea una nueva SessionFactory
	 * @return Instancia de SessionFactory
	 */
	public synchronized static SessionFactory createSessionFactory() {
		if(sessionFactory == null){
			Configuration configuration = new Configuration();
			configuration.configure();
			serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
					configuration.getProperties()).build();
			sessionFactory = configuration.buildSessionFactory(serviceRegistry);
		}
	    return sessionFactory;
	}
	
	/**
	 * Ejecuta una operación en la Sesión
	 * @param Operacion
	 * @return Efecto
	 */
	public static <T> T runInSession(Operation<T> cmd){
		SessionFactory sessionFactory = SessionManager.createSessionFactory();
		Transaction transaction = null;
		T result = null;
		Session session = getSession();
		
		try {
			if(session == null){
			session = sessionFactory.openSession();
			tlSession.set(session);
			
			}
			transaction = session.beginTransaction();
			
			
			result = cmd.execute();

			session.flush();
			transaction.commit();
		} catch (Exception e) {
			if (transaction != null)
				transaction.rollback();
			throw new RuntimeException(e);
		} finally {
			if (session != null)
				session.close();
			tlSession.set(null);
		}
		
		return result;
	}
	
	
	/**
	 * Obtiene la session
	 * @return nos devuelve la session actual.
	 */
	public static Session getSession() {
		return tlSession.get();
	}
	
	
	
// ////////////////	
// Neo4j Setup	///
// ///////////////
	
	
	
	public synchronized static GraphDatabaseService createGraphSession(){
		if (graphDB == null){
			graphDB = new GraphDatabaseFactory().newEmbeddedDatabase("target/neo4j");
			graphSession.set(graphDB);
			registerShutdownHook();
			
		}
			return graphDB;
	}
	

	public static <T> T doTransaction(Operation<T> cmd){
	graphSession.set(createGraphSession());
	GraphDatabaseService gs = graphSession.get();
	T result = null;
		org.neo4j.graphdb.Transaction tx = gs.beginTx();
	try {
		result = cmd.execute();
		
        
    } finally {
    	tx.success();
    }
		return result;
	}
	
	
	public static GraphDatabaseService getGraphSession() {
		return graphSession.get();
	}


	public void shutDown() {
	    graphDB.shutdown();
	}

	public static void registerShutdownHook() {
	    Runtime.getRuntime().addShutdownHook(new Thread() {
	        @Override
	        public void run() {
	            graphDB.shutdown();
	        }
	    });
	}
// ////////////////////////
// Setup MongoDB		//
// //////////////////////
	
	
	public synchronized static DB MongoClient() {
		if (mongoService == null){
			try {
				String path = "mongodb://localhost/comentarios";
				MongoClientURI uri = new MongoClientURI(path);
				mongoService = new MongoClient(uri);
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}
			MongoSession.set(mongoService.getDB("Comentarios"));
		}
			return MongoSession.get();
	}
	

	
}